CSS 继承与优先级的概念
!important
声明
标记了 !important
的声明会被当作更高优先级的来源,因此总体的优先级按照由高到低
排列如下所示:
- 作者的
!important
- 作者
- 用户代理
层叠独立地解决了网页中每个元素的样式属性的冲突。例如,如果给段落设置加粗的字体,用户代理的上下外边距样式仍然会生效(除非被明确覆盖)。
但是它虽然可能 !important
解决了眼前的问题,但是会在以后带来更多问题。一旦给很多声明加上 !important
,要覆盖已设置为 !important
的声明时,该怎么做呢?当给一些声明加上 !important
时,就会先比较来源,再使用常规的优先级规则。最终会让一切回到起点:一旦引入一个 !important
,就会带来更多的 !important
。
因此尽量使用更高优先级的选择器来覆盖样式,而不是使用 !important
。
选择器优先级
第一个选择器的优先级高于第二个选择器。因为不同类型的选择器有不同的优先级。比如,ID 选择器比类选择器优先级更高。同理,类选择器的优先级比标签选择器(也称类型选择器)更高。
优先级的准确规则如下:
- 如果选择器的 ID 数量更多,则它会胜出(即它更明确)。
- 如果 ID 数量一致,那么拥有最多类的选择器胜出。
- 如果以上两次比较都一致,那么拥有最多标签名的选择器胜出。
如果要覆盖一个 ID 选择器的样式,就必须要用另一个 ID 选择器,而 ID 是唯一的,所以尽量不要用 ID 属性,不过可以用 !important
去覆盖样式。
下面介绍一下 优先级标记 的概念,一个常用的表示优先级的方式是用数值形式来标记,通常用逗号隔开每个数。比如,“1,2,3” 表示选择器由 1 个 ID、2 个类、3 个标签组成。优先级最高的 ID 列为第一位,紧接着是类,最后是标签。
例如:
- 选择器
#page-header #page-title
有 2 个 ID,没有类,也没有标签,它的优先级可以用 “2,0,0” 表示。 - 选择器
ul li
有 2 个标签,没有 ID,也没有类名,它的优先级可以用“0,0,2”表示。
如下表所示:
现在通过比较数值就能决定哪个选择器优先级更高(更明确)。“1,0,0” 的优先级高于 “0,2,2” 甚至 “0,10,0”(尽管我不推荐写一个长达 10 个类名的选择器),因为第一个数(ID)有最高优先级。
有时,人们还会用 4 个数的标记,其中将最重要的位置用 0 或 1 来表示,代表一个声明是否是用行内样式添加的。
此时,行内样式 的优先级为 “1,0,0,0”。它会覆盖通过选择器添加的样式,比如优先级为 “0,1,2,0”(1 个 ID 和 2 个类)的选择器。
综上,开发的时候应该尽可能的使用优先级低的样式,这样当需要覆盖一些样式时,才能有选择空间。
继承
如果一个元素的某个属性没有层叠值,则可能会继承某个祖先元素的值。比如通常会给 <body>
元素加上 font-family,里面的所有后代元素都会继承这个字体,就不必给页面的每个元素明确指定字体了。下图展示了继承是如何顺着 DOM 树向下传递的。
但不是所有的属性都能被继承。默认情况下,只有特定的一些属性能被继承,通常是我们希望被继承的那些。它们主要是跟文本相关的属性:
color、font、font-family、font-size、
font-weight、font-variant、font-style、line-height、letter-spacing、text-align、
text-indent、text-transform、white-space 以及 word-spacing。
还有一些其他的属性也可以被继承,比如:
- 列表属性:list-style、list-style-type、list-style-position 以及 list-style-image;
- 表格的边框属性 border-collapse 和 border-spacing 也能被继承。
注意,这些属性控制的是表格的边框行为,而不是常用于指定非表格元素边框的属性。(恐怕没人希望将一个 <div>
的边框传递到每一个后代元素。)以上为不完全枚举,但是已经很详尽了。
源码顺序
层叠的第三步,也是最后一步,是源码顺序。如果两个声明的来源和优先级相同,其中一个声明在样式表中出现较晚,或者位于页面较晚引入的样式表中,则该声明胜出
也就是说,可以通过控制源码顺序,来给特殊链接添加样式。如果两个冲突选择器的优先级相同,则出现得较晚的那个胜出。
在这个方法里,选择器优先级相同。源码顺序决定了哪个声明作用于特殊链接,最终产生了橘黄色的特殊按钮。
开发者工具
使用开发者工具能够看到哪些元素应用了哪些样式规则,以及为什么应用这些规则。层叠和继承都是抽象的概念,使用开发者工具是最好的追踪方式。在一个页面元素上点击鼠标右键,选择弹出菜单上的检查元素,就能打开开发者工具,示例如下所示。
特殊值 inherit 和 initial
有两个特殊值可以赋给任意属性,用于控制层叠:inherit 和 initial。
上面继承那一节也描述了不是所有的属性都会继承自父节点,所以得使用下面的这两个关键字来实现继承父亲其它属性的效果
inherit 继承
有时,我们想用继承代替一个层叠值。这时候可以用 inherit 关键字。可以用它来覆盖另一个值,这样该元素就会继承其父元素的值。
假设我们要给网页加上一个浅灰色的页脚。在页脚上有一些链接,但我们不希望这些链接太显眼,因为页脚不是网页的重点。因此要将页脚的链接变成深灰色
<footer class="footer">
© 2016 Wombat Coffee Roasters —
<a href="/terms-of-use">Terms of use</a>
</footer>
第三个规则集覆盖了蓝色的链接色,让页脚链接的层叠值为 inherit。因此,它继承了父元素 <footer>
的颜色。
这么做的好处是,如果页脚发生任何样式改变的话(比如修改第二个规则集,或者被别的样式覆盖),页脚链接的颜色就会跟着页脚其他内容一起改变。比如,当页脚文本变为更深的灰色时,其中的链接也会跟着改变。
initial 撤销样式
有时,你需要撤销作用于某个元素的样式。这可以用 initial 关键字来实现。每一个 CSS 属性都有初始(默认)值。如果将 initial 值赋给某个属性,那么就会有效地将其重置为默认 值,这种操作相当于硬复位了该值。下图展示了给页脚链接赋以 initial 而不是 inherit 时的效果。
因为在大多数浏览器中,黑色是 color 属性的初始值,所以 color: initial 等价于 color: black。
.footer a {
color: initial;
text-decoration: underline;
}
这么做的好处是不需要思考太多。如果想删除一个元素的边框,设置 border: initial 即可。如果想让一个元素恢复到默认宽度,设置 width: initial 即可。
References
- 《深入解析 CSS》